home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / admin / ipfirewa.c < prev    next >
C/C++ Source or Header  |  1996-11-17  |  24KB  |  1,135 lines

  1.  
  2. /*
  3.  * Copyright (c) 1993 Daniel Boulet
  4.  *
  5.  * Redistribution and use in source forms, with and without modification,
  6.  * are permitted provided that this entire comment appears intact.
  7.  *
  8.  * Redistribution in binary form may occur without any restrictions.
  9.  * Obviously, it would be nice if you gave credit where credit is due
  10.  * but requiring it would be too onerous.
  11.  *
  12.  * This software is provided ``AS IS'' without any warranties of any kind.
  13.  *
  14.  */
  15.  
  16. /*
  17.  *  Linux port (c) 1994 Bob Beck
  18.  *
  19.  * Redistribution and use in source forms, with and without modification,
  20.  * are permitted provided that this entire comment appears intact.
  21.  *
  22.  * This software is provided ``AS IS'' without any warranties of any kind.
  23.  *
  24.  */
  25.  
  26. /*
  27.  *    Drastically cleaned up: Alan Cox Dec 1st 1994.
  28.  */
  29.  
  30. /*
  31.  * Command line interface for IP firewall facility
  32.  */
  33.  
  34. /* $Header: /usr/brule/dept/beck/ipfirewall/RCS/ipfirewall.c,v 1.1 1994/07/28 00:06:11 beck Exp $ */
  35. /* $Log: ipfirewall.c,v $
  36.  * Revision 1.1  1994/07/28  00:06:11  beck
  37.  * Initial revision
  38.  * */
  39.  
  40.  
  41. #include <sys/types.h>
  42. #ifdef _LINUX_TYPES_H
  43. /* Yep. it's Linux */
  44. #ifndef LINUX
  45. #define LINUX
  46. #endif
  47. #endif
  48. #include <sys/socket.h>
  49. #define IPFIREWALL
  50. #include <netinet/in.h>
  51. #include <netinet/in_system.h>
  52. #include <netinet/ip.h>
  53. #include <netinet/tcp.h>
  54. #include <netinet/udp.h>
  55. #ifndef LINUX
  56. #include <netinet/ip_fw.h>
  57. #else
  58. #include <linux/ip_fw.h>    /* Until it gets into stdinc */
  59. #endif
  60. #include <netdb.h>
  61. #include <stdio.h>
  62. #include <stdlib.h>
  63. #include <string.h>
  64. #include <errno.h>
  65. #ifdef LINUX
  66. #include <ctype.h>
  67. #define IPVERSION 4
  68. #endif
  69.  
  70. typedef enum
  71. {
  72.     IPF_BLOCKING = 0,
  73.     IPF_FORWARDING = 1,
  74.     IPF_ACCOUNTING = 2
  75. } ipf_kind;
  76.  
  77. static char *ipf_names[3] =
  78.     {"blocking", "forwarding", "accounting"};
  79. static long ipf_addfunc[3] =
  80.     {IP_FW_ADD_BLK, IP_FW_ADD_FWD, IP_ACCT_ADD};
  81. static long ipf_delfunc[3] =
  82.     {IP_FW_DEL_BLK, IP_FW_DEL_FWD, IP_ACCT_DEL};
  83.  
  84.  
  85. void
  86. show_usage ()
  87. {
  88.     fprintf (stderr, "ipfirewall:  {\n");
  89.     fprintf (stderr, "               list ...\n");
  90.     fprintf (stderr, "             |\n");
  91.     fprintf (stderr, "               flush\n");
  92.     fprintf (stderr, "             |\n");
  93.     fprintf (stderr, "               checkb[locking] ...\n");
  94.     fprintf (stderr, "             |\n");
  95.     fprintf (stderr, "               checkf[orwarding] ...\n");
  96.     fprintf (stderr, "             |\n");
  97.     fprintf (stderr, "               addb[lock] ...\n");
  98.     fprintf (stderr, "             |\n");
  99.     fprintf (stderr, "               addf[orwarding] ...\n");
  100.     fprintf (stderr, "             }\n");
  101.     fprintf (stderr, "               adda[ccounting] ...\n");
  102.     fprintf (stderr, "             }\n");
  103. }
  104.  
  105. /*
  106.  * I'm not sure that this is practical ...
  107.  */
  108.  
  109. void
  110. show_help ()
  111. {
  112.     abort ();
  113.     fprintf (stderr, "ipfirewall:  {\n");
  114.     fprintf (stderr, "               list\n");
  115.     fprintf (stderr, "             |\n");
  116.     fprintf (stderr, "               flush\n");
  117.     fprintf (stderr, "             |\n");
  118.     fprintf (stderr, "               checkb[locking] <type> <src> <dest>\n");
  119.     fprintf (stderr, "             |\n");
  120.     fprintf (stderr, "               checkf[orwarding] <type> <src> <dest>\n");
  121.     fprintf (stderr, "             |\n");
  122.     fprintf (stderr, "               addb[lock] <type> <src> <dest>\n");
  123.     fprintf (stderr, "             |\n");
  124.     fprintf (stderr, "               addf[orwarding] <type> <src> <dest>\n");
  125.     fprintf (stderr, "             }\n");
  126.     fprintf (stderr, "               adda[ccounting] <type> <src> <dest>\n");
  127.     fprintf (stderr, "             }\n");
  128.     fprintf (stderr, "where\n");
  129.     fprintf (stderr, "       <src> ::= <host>:<port> /* for TCP or UDP */\n");
  130.     fprintf (stderr, "       <src> ::= <host>        /* for ICMP */\n");
  131.     fprintf (stderr, "      <host> ::= <byte>.<byte>.<byte>.<byte> | <hostname>\n");
  132.     fprintf (stderr, "      <port> ::= <short> | <servicename>\n");
  133.     fprintf (stderr, "     <short> ::= an integer in the range 1-65535\n");
  134.     fprintf (stderr, "      <byte> ::= an integer in the range 0-255\n");
  135. }
  136.  
  137. static
  138. char *
  139. fmtip (u_long uaddr)
  140. {
  141.     static char tbuf[100];
  142.  
  143.     sprintf (tbuf, "%d.%d.%d.%d",
  144.          ((char *) &uaddr)[0] & 0xff,
  145.          ((char *) &uaddr)[1] & 0xff,
  146.          ((char *) &uaddr)[2] & 0xff,
  147.          ((char *) &uaddr)[3] & 0xff);
  148.  
  149.     return (&tbuf[0]);
  150. }
  151.  
  152. static
  153. void
  154. print_ports (int cnt, int range, u_short * ports)
  155. {
  156.     int ix;
  157.     char *pad;
  158.  
  159.     if (range)
  160.     {
  161.         if (cnt < 2)
  162.         {
  163.             fprintf (stderr, "ipfirewall:  range flag set but only %d ports\n", cnt);
  164.             abort ();
  165.         }
  166.         printf ("%d:%d", ports[0], ports[1]);
  167.         ix = 2;
  168.         pad = " ";
  169.     }
  170.     else
  171.     {
  172.         ix = 0;
  173.         pad = "";
  174.     }
  175.  
  176.     while (ix < cnt)
  177.     {
  178.         printf ("%s%d", pad, ports[ix]);
  179.         pad = " ";
  180.         ix += 1;
  181.     }
  182. }
  183.  
  184. int
  185. do_setsockopt (char *what, int fd, int proto, int cmd, void *data, int datalen, int ok_errno)
  186. {
  187.     char *cmdname;
  188.  
  189.     switch (cmd)
  190.     {
  191.     case IP_FW_FLUSH:
  192.         cmdname = "IP_FW_FLUSH";
  193.         break;
  194.     case IP_FW_CHK_BLK:
  195.         cmdname = "IP_FW_CHK_BLK";
  196.         break;
  197.     case IP_FW_CHK_FWD:
  198.         cmdname = "IP_FW_CHK_FWD";
  199.         break;
  200.     case IP_FW_ADD_BLK:
  201.         cmdname = "IP_FW_ADD_BLK";
  202.         break;
  203.     case IP_FW_ADD_FWD:
  204.         cmdname = "IP_FW_ADD_FWD";
  205.         break;
  206.     case IP_FW_DEL_BLK:
  207.         cmdname = "IP_FW_DEL_BLK";
  208.         break;
  209.     case IP_FW_DEL_FWD:
  210.         cmdname = "IP_FW_DEL_FWD";
  211.         break;
  212.     case IP_ACCT_ADD:
  213.         cmdname = "IP_ACCT_ADD";
  214.         break;
  215.     case IP_ACCT_DEL:
  216.         cmdname = "IP_ACCT_DEL";
  217.         break;
  218.     default:
  219.         fprintf (stderr, "ipfirewall:  unknown command (%d) passed to do_setsockopt - bye!\n", cmd);
  220.         abort ();
  221.     }
  222.  
  223.     if (fd < 0)
  224.     {
  225.         printf ("setsockopt(%d, %d, %s, 0x%x, 0x%x)\n", fd, proto, cmdname, (int) data, datalen);
  226.         if (cmd == IP_FW_CHK_BLK || cmd == IP_FW_CHK_FWD)
  227.         {
  228.             struct iphdr *ip = (struct iphdr *) data;
  229.             struct tcphdr *tcp = (struct tcphdr *) &(((int *) ip)[ip->ihl]);
  230.             if (ip->ihl != sizeof (struct iphdr) / sizeof (int))
  231.             {
  232.                 fprintf (stderr, "ip header length %d, should be %d\n", ip->ihl, sizeof (struct iphdr) / sizeof (int));
  233.             }
  234.             if (ip->protocol != IPPROTO_TCP && ip->protocol != IPPROTO_UDP)
  235.                 abort ();
  236.             printf ("data = struct iphdr : struct %shdr {\n", ip->protocol == IPPROTO_TCP ? "tcp" : "udp");
  237.             printf ("\tsrc=%s ", fmtip (ip->saddr));
  238.             printf ("%d\n", ntohs (tcp->th_sport));
  239.             printf ("\tdst=%s  ", fmtip (ip->daddr));
  240.             printf ("%d\n", ntohs (tcp->th_dport));
  241.             printf ("}\n");
  242.         }
  243.         else if (cmd == IP_FW_ADD_BLK || cmd == IP_FW_ADD_FWD || cmd == IP_ACCT_ADD)
  244.         {
  245.             struct ip_fw *fp = (struct ip_fw *) data;
  246.             int fmt_ports;
  247.             printf ("data = struct ip_fw {\n");
  248.             if (fp->flags & IP_FW_F_ACCEPT)
  249.             {
  250.                 printf ("\taccept ");
  251.             }
  252.             else
  253.             {
  254.                 printf ("\tdeny ");
  255.             }
  256.             switch (fp->flags & IP_FW_F_KIND)
  257.             {
  258.             case IP_FW_F_ALL:
  259.                 printf ("\tuniversal\n");
  260.                 fmt_ports = 0;
  261.                 break;
  262.             case IP_FW_F_TCP:
  263.                 printf ("tcp\n");
  264.                 fmt_ports = 1;
  265.                 break;
  266.             case IP_FW_F_UDP:
  267.                 printf ("udp\n");
  268.                 fmt_ports = 1;
  269.                 break;
  270.             case IP_FW_F_ICMP:
  271.                 printf ("icmp\n");
  272.                 fmt_ports = 0;
  273.                 break;
  274.             }
  275.             printf ("\tsrc=%s:", fmtip (fp->src.s_addr));
  276.             printf ("%s ", fmtip (fp->src_mask.s_addr));
  277.             if (fmt_ports)
  278.             {
  279.                 print_ports (fp->n_src_p, fp->flags & IP_FW_F_SRNG, &fp->ports[0]);
  280.             }
  281.             else if (fp->flags & (IP_FW_F_SRNG | IP_FW_F_DRNG))
  282.             {
  283.                 abort ();
  284.             }
  285.             else if (fp->n_src_p > 0 || fp->n_dst_p > 0)
  286.             {
  287.                 abort ();
  288.             }
  289.             printf ("\n");
  290.             printf ("\tdst=%s:", fmtip (fp->dst.s_addr));
  291.             printf ("%s ", fmtip (fp->dst_mask.s_addr));
  292.             if (fmt_ports)
  293.             {
  294.                 print_ports (fp->n_dst_p, fp->flags & IP_FW_F_DRNG, &fp->ports[fp->n_src_p]);
  295.             }
  296.             printf ("\n");
  297.             printf ("}\n");
  298.         }
  299.     }
  300.     else
  301.     {
  302.         if (setsockopt (fd, proto, cmd, data, datalen) < 0)
  303.         {
  304.             if (errno == ok_errno)
  305.             {
  306.                 return (errno);
  307.             }
  308.             perror ("ipfirewall:  setsockopt");
  309.             exit (1);
  310.         }
  311.     }
  312.     return (0);
  313. }
  314.  
  315. void
  316. show_parms (char **argv)
  317. {
  318.     while (*argv)
  319.     {
  320.         printf ("%s ", *argv++);
  321.     }
  322. }
  323.  
  324. int
  325. get_protocol (char *arg, void (*cmd_usage) (ipf_kind), ipf_kind kind)
  326. {
  327.     if (arg == NULL)
  328.     {
  329.         fprintf (stderr, "ipfirewall:  missing protocol name\n");
  330.     }
  331.     else if (strcmp (arg, "tcp") == 0)
  332.     {
  333.         return (IP_FW_F_TCP);
  334.     }
  335.     else if (strcmp (arg, "udp") == 0)
  336.     {
  337.         return (IP_FW_F_UDP);
  338.     }
  339.     else if (strcmp (arg, "icmp") == 0)
  340.     {
  341.         return (IP_FW_F_ICMP);
  342.     }
  343.     else if (strcmp (arg, "all") == 0)
  344.     {
  345.         return (IP_FW_F_ALL);
  346.     }
  347.     else
  348.     {
  349.         fprintf (stderr, "illegal protocol name \"%s\"\n", arg);
  350.     }
  351.     (*cmd_usage) (kind);
  352.     exit (1);
  353.     return (0);
  354. }
  355.  
  356. void
  357. get_ipaddr (char *arg, struct in_addr *addr, struct in_addr *mask, void (*usage) (ipf_kind), ipf_kind kind)
  358. {
  359.     char *p, *tbuf;
  360.     int period_cnt, non_digit;
  361.     struct hostent *hptr;
  362.  
  363.     if (arg == NULL)
  364.     {
  365.         fprintf (stderr, "ipfirewall:  missing ip address\n");
  366.         exit (1);
  367.     }
  368.  
  369.     period_cnt = 0;
  370.     non_digit = 0;
  371.     for (p = arg; *p != '\0' && *p != '/' && *p != ':'; p += 1)
  372.     {
  373.         if (*p == '.')
  374.         {
  375.             if (p > arg && *(p - 1) == '.')
  376.             {
  377.                 fprintf (stderr, "ipfirewall:  two periods in a row in ip address (%s)\n", arg);
  378.                 exit (1);
  379.             }
  380.             period_cnt += 1;
  381.         }
  382.         else if (!isdigit (*p))
  383.         {
  384.             non_digit = 1;
  385.         }
  386.     }
  387.  
  388.     tbuf = malloc (p - arg + 1);
  389.     strncpy (tbuf, arg, p - arg);
  390.     tbuf[p - arg] = '\0';
  391.  
  392.     if (non_digit)
  393.     {
  394.  
  395.         hptr = gethostbyname (tbuf);
  396.         if (hptr == NULL)
  397.         {
  398.             fprintf (stderr, "ipfirewall:  unknown host \"%s\"\n", tbuf);
  399.             exit (1);
  400.         }
  401.         if (hptr->h_length != sizeof (struct in_addr))
  402.         {
  403.             fprintf (stderr, "ipfirewall:  hostentry addr length = %d, expected %d (i.e. sizeof(struct in_addr))\n",
  404.                  hptr->h_length, sizeof (struct in_addr));
  405.             exit (1);
  406.         }
  407.  
  408.         bcopy (hptr->h_addr, addr, sizeof (struct in_addr));
  409.  
  410.     }
  411.     else
  412.     {
  413.  
  414.         if (period_cnt == 3)
  415.         {
  416.  
  417.             int a1, a2, a3, a4, matched;
  418.  
  419.             if ((matched = sscanf (tbuf, "%d.%d.%d.%d", &a1, &a2, &a3, &a4))
  420.                 != 4)
  421.             {
  422.                 fprintf (stderr,
  423.                      "ipfirewall: Only %d fields matched in IP address!\n",
  424.                      matched);
  425.                 /* should this exit here? or catch it later? -BB */
  426.             }
  427.  
  428.             if (a1 > 255 || a2 > 255 || a3 > 255 || a4 > 255)
  429.             {
  430.                 fprintf (stderr, "ipfirewall:  number too large in ip address (%s)\n", arg);
  431.                 exit (1);
  432.             }
  433.  
  434.             ((char *) addr)[0] = a1;
  435.             ((char *) addr)[1] = a2;
  436.             ((char *) addr)[2] = a3;
  437.             ((char *) addr)[3] = a4;
  438.  
  439.         }
  440.         else if (strcmp (tbuf, "0") == 0)
  441.         {
  442.  
  443.             ((char *) addr)[0] = 0;
  444.             ((char *) addr)[1] = 0;
  445.             ((char *) addr)[2] = 0;
  446.             ((char *) addr)[3] = 0;
  447.  
  448.         }
  449.         else
  450.         {
  451.  
  452.             fprintf (stderr, "ipfirewall:  incorrect ip address format \"%s\" (expected 3 periods)\n", tbuf);
  453.             exit (1);
  454.  
  455.         }
  456.  
  457.     }
  458.  
  459.     free (tbuf);
  460.  
  461.     if (mask == NULL)
  462.     {
  463.  
  464.         if (*p != '\0')
  465.         {
  466.             fprintf (stderr, "ipfirewall:  ip netmask not allowed here (%s)\n", (char *) addr);
  467.             exit (1);
  468.         }
  469.  
  470.     }
  471.     else
  472.     {
  473.  
  474.         if (*p == ':')
  475.         {
  476.  
  477.             get_ipaddr (p + 1, mask, NULL, usage, kind);
  478.  
  479.         }
  480.         else if (*p == '/')
  481.         {
  482.  
  483.             int bits;
  484.             char *end;
  485.  
  486.             p += 1;
  487.             if (*p == '\0')
  488.             {
  489.                 fprintf (stderr, "ipfirewall:  missing mask value (%s)\n", arg);
  490.                 exit (1);
  491.             }
  492.             else if (!isdigit (*p))
  493.             {
  494.                 fprintf (stderr, "ipfirewall:  non-numeric mask value (%s)\n", arg);
  495.                 exit (1);
  496.             }
  497.  
  498.             bits = strtol (p, &end, 10);
  499.             if (*end != '\0')
  500.             {
  501.                 fprintf (stderr, "ipfirewall:  junk after mask (%s)\n", arg);
  502.                 exit (1);
  503.             }
  504.  
  505.             if (bits < 0 || bits > sizeof (u_long) * 8)
  506.             {
  507.                 fprintf (stderr, "ipfirewall:  mask length value out of range (%s)\n", arg);
  508.                 exit (1);
  509.             }
  510.  
  511.             if (bits == 0)
  512.             {    /* left shifts of 32 aren't defined */
  513.                 mask->s_addr = 0;
  514.             }
  515.             else
  516.             {
  517.                 ((char *) mask)[0] = (-1 << (32 - bits)) >> 24;
  518.                 ((char *) mask)[1] = (-1 << (32 - bits)) >> 16;
  519.                 ((char *) mask)[2] = (-1 << (32 - bits)) >> 8;
  520.                 ((char *) mask)[3] = (-1 << (32 - bits)) >> 0;
  521.             }
  522.  
  523.         }
  524.         else if (*p == '\0')
  525.         {
  526.             mask->s_addr = 0xffffffff;
  527.         }
  528.         else
  529.         {
  530.  
  531.             fprintf (stderr, "ipfirewall:  junk after ip address (%s)\n", arg);
  532.             exit (1);
  533.  
  534.         }
  535.  
  536.         /*
  537.      * Mask off any bits in the address that are zero in the mask.
  538.      * This allows the user to describe a network by specifying
  539.      * any host on the network masked with the network's netmask.
  540.      */
  541.         addr->s_addr &= mask->s_addr;
  542.  
  543.     }
  544.  
  545. }
  546.  
  547. u_short
  548. get_one_port (char *arg, void (*usage) (ipf_kind), ipf_kind kind, const char *proto_name)
  549. {
  550.     int slen = strlen (arg);
  551.  
  552.     if (slen > 0 && strspn (arg, "0123456789") == slen)
  553.     {
  554.         int port;
  555.         char *end;
  556.  
  557.         port = strtol (arg, &end, 10);
  558.         if (*end != '\0')
  559.         {
  560.             fprintf (stderr, "ipfirewall:  illegal port number (%s)\n", arg);
  561.             exit (1);
  562.         }
  563.  
  564.         if (port <= 0 || port > 65535)
  565.         {
  566.             fprintf (stderr, "ipfirewall:  port number out of range (%d)\n", port);
  567.             exit (1);
  568.         }
  569.  
  570.         return (port);
  571.  
  572.     }
  573.     else
  574.     {
  575.  
  576.         struct servent *sptr;
  577.  
  578.         sptr = getservbyname (arg, proto_name);
  579.  
  580.         if (sptr == NULL)
  581.         {
  582.             fprintf (stderr, "ipfirewall:  unknown %s service \"%s\"\n", proto_name, arg);
  583.             exit (1);
  584.         }
  585.  
  586.         return (ntohs (sptr->s_port));
  587.  
  588.     }
  589.  
  590. }
  591.  
  592. int
  593. get_ports (char ***argv_ptr, u_short * ports, int min_ports, int max_ports, void (*usage) (ipf_kind), ipf_kind kind, const char *proto_name)
  594. {
  595.     int ix;
  596.     char *arg;
  597.     int sign;
  598.  
  599.     ix = 0;
  600.     sign = 1;
  601.     while ((arg = **argv_ptr) != NULL && strcmp (arg, "from") != 0 && strcmp (arg, "to") != 0)
  602.     {
  603.  
  604.         char *p;
  605.  
  606.     /*
  607.      * Check that we havn't found too many port numbers.
  608.      * We do this here instead of with another condition on the while loop
  609.      * so that the caller can assume that the next parameter is NOT a port number.
  610.      */
  611.  
  612.         if (ix >= max_ports)
  613.         {
  614.             fprintf (stderr, "ipfirewall:  too many port numbers (max %d, got at least %d, next parm=\"%s\")\n", max_ports, max_ports + 1, arg);
  615.             exit (1);
  616.         }
  617.  
  618.         if ((p = strchr (arg, ':')) == NULL)
  619.         {
  620.  
  621.             ports[ix++] = get_one_port (arg, usage, kind, proto_name);
  622.  
  623.         }
  624.         else
  625.         {
  626.  
  627.             if (ix > 0)
  628.             {
  629.  
  630.                 fprintf (stderr, "ipfirewall:  port ranges are only allowed for the first port value pair (%s)\n", arg);
  631.                 exit (1);
  632.  
  633.             }
  634.  
  635.             if (max_ports > 1)
  636.             {
  637.  
  638.                 char *tbuf;
  639.  
  640.                 tbuf = malloc ((p - arg) + 1);
  641.                 strncpy (tbuf, arg, p - arg);
  642.                 tbuf[p - arg] = '\0';
  643.  
  644.                 ports[ix++] = get_one_port (tbuf, usage, kind, proto_name);
  645.                 ports[ix++] = get_one_port (p + 1, usage, kind, proto_name);
  646.                 sign = -1;
  647.  
  648.             }
  649.             else
  650.             {
  651.  
  652.                 fprintf (stderr, "ipfirewall:  port range not allowed here (%s)\n", arg);
  653.                 exit (1);
  654.  
  655.             }
  656.         }
  657.  
  658.         *argv_ptr += 1;
  659.     }
  660.  
  661.     if (ix < min_ports)
  662.     {
  663.         if (min_ports == 1)
  664.         {
  665.             fprintf (stderr, "ipfirewall:  missing port number%s\n", max_ports == 1 ? "" : "(s)");
  666.         }
  667.         else
  668.         {
  669.             fprintf (stderr, "ipfirewall:  not enough port numbers (expected %d, got %d)\n", min_ports, ix);
  670.         }
  671.         exit (1);
  672.     }
  673.  
  674.     return (sign * ix);
  675.  
  676. }
  677.  
  678. void
  679. check_usage (ipf_kind kind)
  680. {
  681.     fprintf (stderr, "usage:  ipfirewall check%s ...\n", ipf_names[kind]);
  682. }
  683.  
  684. void
  685. check (ipf_kind kind, int socket_fd, char **argv)
  686. {
  687.     int protocol;
  688.     struct iphdr *packet;
  689.     char *proto_name;
  690.  
  691.     packet = (struct iphdr *) malloc (sizeof (struct iphdr) + sizeof (struct tcphdr));
  692.     packet->version = IPVERSION;
  693.     packet->ihl = sizeof (struct iphdr) / sizeof (int);
  694.     printf ("check%s ", kind == IPF_BLOCKING ? "blocking" : "forwarding");
  695.     show_parms (argv);
  696.     printf ("\n");
  697.  
  698.     proto_name = *argv++;
  699.     protocol = get_protocol (proto_name, check_usage, kind);
  700.     switch (protocol)
  701.     {
  702.     case IP_FW_F_TCP:
  703.         packet->protocol = IPPROTO_TCP;
  704.         break;
  705.     case IP_FW_F_UDP:
  706.         packet->protocol = IPPROTO_UDP;
  707.         break;
  708.     default:
  709.         fprintf (stderr, "ipfirewall:  can only check TCP or UDP packets\n");
  710.         break;
  711.     }
  712.  
  713.     if (*argv == NULL)
  714.     {
  715.         fprintf (stderr, "ipfirewall:  missing \"from\" from keyword\n");
  716.         exit (1);
  717.     }
  718.     if (strcmp (*argv, "from") == 0)
  719.     {
  720.         argv += 1;
  721.         get_ipaddr (*argv++, (struct in_addr *) &packet->saddr, NULL, check_usage, kind);
  722.         if (protocol == IP_FW_F_TCP || protocol == IP_FW_F_UDP)
  723.         {
  724.             get_ports (&argv, &((struct tcphdr *) (&packet[1]))->th_sport, 1, 1, check_usage, kind, proto_name);
  725.             ((struct tcphdr *) (&packet[1]))->th_sport = htons (
  726.                   ((struct tcphdr *) (&packet[1]))->th_sport
  727.                 );
  728.         }
  729.     }
  730.     else
  731.     {
  732.         fprintf (stderr, "ipfirewall:  expected \"from\" keyword, got \"%s\"\n", *argv);
  733.         exit (1);
  734.     }
  735.  
  736.     if (*argv == NULL)
  737.     {
  738.         fprintf (stderr, "ipfirewall:  missing \"to\" from keyword\n");
  739.         exit (1);
  740.     }
  741.     if (strcmp (*argv, "to") == 0)
  742.     {
  743.         argv += 1;
  744.         get_ipaddr (*argv++, (struct in_addr *) &packet->daddr, NULL, check_usage, kind);
  745.         if (protocol == IP_FW_F_TCP || protocol == IP_FW_F_UDP)
  746.         {
  747.             get_ports (&argv, &((struct tcphdr *) (&packet[1]))->th_dport, 1, 1, check_usage, kind, proto_name);
  748.             ((struct tcphdr *) (&packet[1]))->th_dport = htons (
  749.                   ((struct tcphdr *) (&packet[1]))->th_dport
  750.                 );
  751.         }
  752.     }
  753.     else
  754.     {
  755.         fprintf (stderr, "ipfirewall:  expected \"to\" keyword, got \"%s\"\n", *argv);
  756.         exit (1);
  757.     }
  758.  
  759.     if (*argv == NULL)
  760.     {
  761.  
  762.         if (do_setsockopt (kind == IPF_BLOCKING ? "checkblocking" : "checkforwarding",
  763.                    socket_fd, IPPROTO_IP,
  764.                kind == IPF_BLOCKING ? IP_FW_CHK_BLK : IP_FW_CHK_FWD,
  765.                    packet,
  766.                  sizeof (struct iphdr) + sizeof (struct tcphdr),
  767.                    EACCES
  768.             ) == 0
  769.         )
  770.         {
  771.             printf ("packet accepted by %s firewall\n",
  772.               kind == IPF_BLOCKING ? "blocking" : "forwarding");
  773.         }
  774.         else
  775.         {
  776.             printf ("packet rejected by %s firewall\n",
  777.               kind == IPF_BLOCKING ? "blocking" : "forwarding");
  778.         }
  779.  
  780.         return;
  781.  
  782.     }
  783.     else
  784.     {
  785.         fprintf (stderr, "ipfirewall:  extra parameters at end of command (");
  786.         show_parms (argv);
  787.         fprintf (stderr, ")\n");
  788.         exit (1);
  789.     }
  790. }
  791.  
  792. void
  793. add_usage (ipf_kind kind)
  794. {
  795.     fprintf (stderr, "usage:  ipfirewall add%s ...\n", ipf_names[kind]);
  796. }
  797.  
  798. void
  799. add (ipf_kind kind, int socket_fd, char **argv)
  800. {
  801.     int protocol, accept_firewall, src_range, dst_range;
  802.     struct ip_fw firewall;
  803.     char *proto_name;
  804.  
  805.     printf ("add%s ", ipf_names[kind]);
  806.     show_parms (argv);
  807.     printf ("\n");
  808.  
  809.     if (kind != IPF_ACCOUNTING)
  810.     {
  811.  
  812.         if (*argv == NULL)
  813.         {
  814.             fprintf (stderr, "ipfirewall:  missing \"accept\" or \"deny\" keyword\n");
  815.             exit (1);
  816.         }
  817.  
  818.         if (strcmp (*argv, "deny") == 0)
  819.         {
  820.             accept_firewall = 0;
  821.         }
  822.         else if (strcmp (*argv, "accept") == 0)
  823.         {
  824.             accept_firewall = IP_FW_F_ACCEPT;
  825.         }
  826.         else
  827.         {
  828.             fprintf (stderr, "ipfirewall:  expected \"accept\" or \"deny\", got \"%s\"\n", *argv);
  829.             exit (1);
  830.         }
  831.  
  832.         argv += 1;
  833.     }
  834.     else
  835.         accept_firewall = 0;
  836.     proto_name = *argv++;
  837.     protocol = get_protocol (proto_name, add_usage, kind);
  838.  
  839.     if (*argv == NULL)
  840.     {
  841.         fprintf (stderr, "ipfirewall:  missing \"from\" keyword\n");
  842.         exit (1);
  843.     }
  844.     if (strcmp (*argv, "from") == 0)
  845.     {
  846.         argv++;
  847.         get_ipaddr (*argv++, &firewall.src, &firewall.src_mask, add_usage, kind);
  848.         if (protocol == IP_FW_F_TCP || protocol == IP_FW_F_UDP)
  849.         {
  850.             int cnt;
  851.             cnt = get_ports (&argv, &firewall.ports[0], 0, IP_FW_MAX_PORTS, add_usage, kind, proto_name);
  852.             if (cnt < 0)
  853.             {
  854.                 src_range = IP_FW_F_SRNG;
  855.                 cnt = -cnt;
  856.             }
  857.             else
  858.             {
  859.                 src_range = 0;
  860.             }
  861.             firewall.n_src_p = cnt;
  862.         }
  863.         else
  864.         {
  865.             firewall.n_src_p = 0;
  866.             src_range = 0;
  867.         }
  868.     }
  869.     else
  870.     {
  871.         fprintf (stderr, "ipfirewall:  expected \"from\", got \"%s\"\n", *argv);
  872.         exit (1);
  873.     }
  874.  
  875.     if (*argv == NULL)
  876.     {
  877.         fprintf (stderr, "ipfirewall:  missing \"to\" keyword\n");
  878.         exit (1);
  879.     }
  880.     if (strcmp (*argv, "to") == 0)
  881.     {
  882.         argv++;
  883.         get_ipaddr (*argv++, &firewall.dst, &firewall.dst_mask, add_usage, kind);
  884.         if (protocol == IP_FW_F_TCP || protocol == IP_FW_F_UDP)
  885.         {
  886.             int cnt;
  887.             cnt = get_ports (&argv, &firewall.ports[firewall.n_src_p], 0, IP_FW_MAX_PORTS - firewall.n_src_p, add_usage, kind, proto_name);
  888.             if (cnt < 0)
  889.             {
  890.                 dst_range = IP_FW_F_DRNG;
  891.                 cnt = -cnt;
  892.             }
  893.             else
  894.             {
  895.                 dst_range = 0;
  896.             }
  897.             firewall.n_dst_p = cnt;
  898.         }
  899.         else
  900.         {
  901.             firewall.n_dst_p = 0;
  902.             dst_range = 0;
  903.         }
  904.     }
  905.     else
  906.     {
  907.         fprintf (stderr, "ipfirewall:  expected \"to\", got \"%s\"\n", *argv);
  908.         exit (1);
  909.     }
  910.  
  911.     if (*argv == NULL)
  912.     {
  913.  
  914.         firewall.flags = protocol | accept_firewall | src_range | dst_range;
  915.         (void) do_setsockopt (ipf_names[kind],
  916.                       socket_fd, IPPROTO_IP,
  917.                       ipf_addfunc[kind],
  918.                       &firewall,
  919.                       sizeof (firewall),
  920.                       0
  921.             );
  922.  
  923.     }
  924.     else
  925.     {
  926.         fprintf (stderr, "ipfirewall:  extra parameters at end of command (");
  927.         show_parms (argv);
  928.         fprintf (stderr, ")\n");
  929.         exit (1);
  930.     }
  931. }
  932.  
  933. static int count_mask(unsigned long mask)
  934. {
  935.     int ct;
  936.     for(ct=0;(mask&0x80000000);ct++)
  937.         mask<<=1;
  938.     return ct;
  939. }
  940.  
  941. void list_file(char *path, int acct)
  942. {
  943.     FILE * f=fopen(path,"r");
  944.     char buf[256];
  945.     unsigned long sa,da,sm,dm;
  946.     unsigned short nsp, ndp;
  947.     unsigned long npkt, nbyt;
  948.     unsigned int ports[10];
  949.     int flags;
  950.     if(f==NULL)
  951.     {
  952.         perror(path);
  953.         exit(1);
  954.     }
  955.     fgets(buf,255,f);    /* Title */
  956.     while(fgets(buf,255,f))
  957.     {
  958.         unsigned int *pp=&ports[0];
  959.         sscanf(buf,"%lX/%lX->%lX/%lX %X %u %u %lu %lu %u %u %u %u %u %u %u %u %u %u",
  960.             &sa,&sm,&da,&dm,&flags, &nsp, &ndp, &npkt, &nbyt,
  961.             &ports[0],&ports[1],&ports[2],&ports[3],&ports[4],
  962.             &ports[5],&ports[6],&ports[7],&ports[8],&ports[9]);
  963.         
  964.         if(!acct)
  965.         {
  966.             if(flags&IP_FW_F_ACCEPT)
  967.                 printf("Accept ");
  968.             else
  969.                 printf("Reject ");
  970.         }
  971.         else
  972.             printf("%lu packets (%lu bytes) matching: ",
  973.                 npkt,nbyt);
  974.                 
  975.         if(flags&IP_FW_F_ALL)
  976.             printf("all  from ");
  977.         else if(flags&IP_FW_F_TCP)
  978.             printf("TCP  from ");
  979.         else if(flags&IP_FW_F_UDP)
  980.             printf("UDP  from ");
  981.         else
  982.             printf("ICMP from ");
  983.         if(sm==0)
  984.             printf("anywhere to ");
  985.         else
  986.             printf("%s/%d to ",fmtip(htonl(sa)),count_mask(sm));
  987.         if(dm==0)
  988.             printf("anywhere");
  989.         else
  990.             printf("%s/%d", fmtip(htonl(da)),count_mask(dm));
  991.         
  992.         if(flags&(IP_FW_F_TCP|IP_FW_F_UDP))
  993.         {
  994.             printf("  Ports: ");
  995.             if(nsp==0)
  996.                 printf("any ");
  997.             else
  998.             {
  999.                 if(flags&IP_FW_F_SRNG)
  1000.                 {    
  1001.                     printf("%u-%u ",pp[0],pp[1]);
  1002.                     pp+=2;
  1003.                     nsp-=2;
  1004.                 }
  1005.                 while(nsp-->0)
  1006.                     printf("%u ",*pp++);
  1007.             }
  1008.             printf("to");
  1009.         
  1010.             if(ndp==0)
  1011.                 printf(" any");
  1012.             else
  1013.             {
  1014.                 if(flags&IP_FW_F_DRNG)
  1015.                 {
  1016.                     printf(" %u-%u",pp[0],pp[1]);
  1017.                     pp+=2;
  1018.                 }
  1019.                 while(ndp-->0)
  1020.                     printf(" %u",*pp++);        
  1021.             }
  1022.         }
  1023.         printf("\n");
  1024.     }
  1025.     fclose(f);
  1026. }
  1027.  
  1028. void list(int socket_fd, char **argv)
  1029. {
  1030.     if(*argv==NULL && **argv)
  1031.     {
  1032.         fprintf(stderr,"blocking, forwarding or accounting keyword expected.\n");
  1033.         exit(1);
  1034.     }
  1035.     if(strncmp(*argv,"blocking",strlen(*argv))==0)
  1036.     {
  1037.         list_file("/proc/net/ip_block",0);
  1038.         return;
  1039.     }
  1040.     if(strncmp(*argv,"forwarding",strlen(*argv))==0)
  1041.     {
  1042.         list_file("/proc/net/ip_forward",0);
  1043.         return;
  1044.     }
  1045.     if(strncmp(*argv,"accounting",strlen(*argv))==0)
  1046.     {
  1047.         list_file("/proc/net/ip_acct",1);
  1048.         return;
  1049.     }
  1050.     fprintf(stderr,"Found '%s': 'blocking', 'forwarding' or 'accounting' keyword expected.\n",*argv);
  1051.     exit(1);
  1052. }
  1053.         
  1054. void
  1055. main (argc, argv)
  1056.      int argc;
  1057.      char **argv;
  1058. {
  1059.     int socket_fd;
  1060.  
  1061.     socket_fd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
  1062.  
  1063.     if (socket_fd < 0)
  1064.     {
  1065.         perror ("ipfirewall:");
  1066.         exit(1);
  1067.     }
  1068.  
  1069.     if (argc == 1)
  1070.     {
  1071.         show_usage ();
  1072.         exit (1);
  1073.     }
  1074.  
  1075.     if (strcmp (argv[1], "list") == 0)
  1076.     {
  1077.         list(socket_fd, &argv[2]);
  1078.     }
  1079.     else if (strcmp (argv[1], "flush") == 0)
  1080.     {
  1081. #ifdef LINUX
  1082.         /* Same kludge as above, see above ranting and griping -BB */
  1083.         unsigned long fred = 1;
  1084.         (void) do_setsockopt (argv[1], socket_fd, IPPROTO_IP, IP_FW_FLUSH, &fred, sizeof (unsigned long), 0);
  1085. #else
  1086.         (void) do_setsockopt (argv[1], socket_fd, IPPROTO_IP, IP_FLUSH_FIREWALLS, NULL, 0, 0);
  1087. #endif
  1088.  
  1089.     }
  1090.     else if (strlen (argv[1]) >= strlen ("checkb")
  1091.            && strncmp (argv[1], "checkblocking", strlen (argv[1])) == 0)
  1092.     {
  1093.  
  1094.         check (IPF_BLOCKING, socket_fd, &argv[2]);
  1095.  
  1096.     }
  1097.     else if (strlen (argv[1]) >= strlen ("checkf")
  1098.          && strncmp (argv[1], "checkforwarding", strlen (argv[1])) == 0)
  1099.     {
  1100.  
  1101.         check (IPF_FORWARDING, socket_fd, &argv[2]);
  1102.  
  1103.     }
  1104.     else if (strlen (argv[1]) >= strlen ("addb")
  1105.          && strncmp (argv[1], "addblocking", strlen (argv[1])) == 0)
  1106.     {
  1107.  
  1108.         add (IPF_BLOCKING, socket_fd, &argv[2]);
  1109.  
  1110.     }
  1111.     else if (strlen (argv[1]) >= strlen ("addf")
  1112.            && strncmp (argv[1], "addforwarding", strlen (argv[1])) == 0)
  1113.     {
  1114.  
  1115.         add (IPF_FORWARDING, socket_fd, &argv[2]);
  1116.  
  1117.     }
  1118.     else if (strlen (argv[1]) >= strlen ("adda")
  1119.            && strncmp (argv[1], "addaccounting", strlen (argv[1])) == 0)
  1120.     {
  1121.  
  1122.         add (IPF_ACCOUNTING, socket_fd, &argv[2]);
  1123.  
  1124.     }
  1125.     else
  1126.     {
  1127.  
  1128.         fprintf (stderr, "ipfirewall:  unknown command \"%s\"\n", argv[1]);
  1129.         show_usage ();
  1130.         exit (1);
  1131.     }
  1132.  
  1133.     exit (0);
  1134. }
  1135.